{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 题目1\n",
    "\n",
    "Boy追求Girl，给Girl送鲜花，送巧克力，送洋娃娃。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "曼曼, 送你洋娃娃\n",
      "曼曼, 送你巧克力\n",
      "曼曼, 送你鲜花\n"
     ]
    }
   ],
   "source": [
    "class Boy():\n",
    "    def __init__(self, girl):\n",
    "        self.girl = girl\n",
    "    \n",
    "    def give_dolls(self):\n",
    "        print(\"{}, 送你洋娃娃\".format(self.girl.name))\n",
    "    \n",
    "    def give_flowers(self):\n",
    "        print(\"{}, 送你鲜花\".format(self.girl.name))\n",
    "\n",
    "    def give_chocolate(self):\n",
    "        print(\"{}, 送你巧克力\".format(self.girl.name))\n",
    "        \n",
    "class Girl():\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "    \n",
    "def main():\n",
    "    mm = Girl(\"曼曼\")\n",
    "    gg = Boy(mm)\n",
    "    \n",
    "    gg.give_dolls()\n",
    "    gg.give_chocolate()\n",
    "    gg.give_flowers()\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 题目2\n",
    "假设Boy并不认识Girl，Boy希望让Proxy帮他把鲜花，巧克力，洋娃娃转交给Girl。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "曼曼, 送你洋娃娃\n",
      "曼曼, 送你巧克力\n",
      "曼曼, 送你鲜花\n"
     ]
    }
   ],
   "source": [
    "class Proxy():\n",
    "    def __init__(self, girl):\n",
    "        self.girl = girl\n",
    "    \n",
    "    def give_dolls(self):\n",
    "        print(\"{}, 送你洋娃娃\".format(self.girl.name))\n",
    "    \n",
    "    def give_flowers(self):\n",
    "        print(\"{}, 送你鲜花\".format(self.girl.name))\n",
    "\n",
    "    def give_chocolate(self):\n",
    "        print(\"{}, 送你巧克力\".format(self.girl.name))\n",
    "        \n",
    "class Girl():\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "    \n",
    "def main():\n",
    "    mm = Girl(\"曼曼\")\n",
    "    proxy = Proxy(mm)\n",
    "    \n",
    "    proxy.give_dolls()\n",
    "    proxy.give_chocolate()\n",
    "    proxy.give_flowers()\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 点评\n",
    "这样看上去的确是Proxy送给Girl的各种礼物，但是这些礼物其实是Boy的，在代码中并没有体现这一点。在代码中如何体现表面上是Proxy送的礼物，实际上是Boy送的礼物呢？这需要用到代理模式，把送礼物封装成接口，然后让Boy和Proxy都去实现这个接口，Boy和Proxy的区别就是Proxy的接口实现要调用Boy的接口实现。\n",
    "\n",
    "Python中没有明确的接口定义方法，抽象接口可以看作编程人员对自己编码行为的约束，让自己按照一定的规矩写代码。为了实现同样的目的，在Python中可以通过定义一个抽象类来达到相同的目的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "曼曼, 送你洋娃娃\n",
      "曼曼, 送你巧克力\n",
      "曼曼, 送你鲜花\n"
     ]
    }
   ],
   "source": [
    "from abc import ABCMeta, abstractmethod\n",
    "\n",
    "\n",
    "class IGiveGift():\n",
    "\n",
    "    __metaclass__ = ABCMeta\n",
    "    \n",
    "    @abstractmethod\n",
    "    def give_dolls(self):\n",
    "        pass\n",
    "    \n",
    "    @abstractmethod\n",
    "    def give_flowers(self):\n",
    "        pass\n",
    "    \n",
    "    @abstractmethod\n",
    "    def give_chocolate(self):\n",
    "        pass\n",
    "    \n",
    "    \n",
    "class Boy(IGiveGift):\n",
    "    \n",
    "    def __init__(self, girl):\n",
    "        self.girl = girl\n",
    "    \n",
    "    def give_dolls(self):\n",
    "        print(\"{}, 送你洋娃娃\".format(self.girl.name))\n",
    "    \n",
    "    def give_flowers(self):\n",
    "        print(\"{}, 送你鲜花\".format(self.girl.name))\n",
    "\n",
    "    def give_chocolate(self):\n",
    "        print(\"{}, 送你巧克力\".format(self.girl.name))\n",
    "        \n",
    "        \n",
    "class Proxy(IGiveGift):\n",
    "    \n",
    "    def __init__(self, girl):\n",
    "        self.gg = Boy(girl)\n",
    "    \n",
    "    def give_dolls(self):\n",
    "        self.gg.give_dolls()\n",
    "    \n",
    "    def give_flowers(self):\n",
    "        self.gg.give_flowers()\n",
    "\n",
    "    def give_chocolate(self):\n",
    "        self.gg.give_chocolate()\n",
    "        \n",
    "def main():\n",
    "    mm = Girl(\"曼曼\")\n",
    "    proxy = Proxy(mm)\n",
    "    \n",
    "    proxy.give_dolls()\n",
    "    proxy.give_chocolate()\n",
    "    proxy.give_flowers()\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 点评\n",
    "现在从代码中可以清晰的看出，表面上是proxy送给Girl mm的礼物，但是其实是Boy gg送的。\n",
    "\n",
    "## 代理模式\n",
    "代理模式，为其他对象提供一种代理以控制对这个对象的访问。在上述场景中，mm和gg并没有直接的联系，即mm和gg互相无法访问到，但是可以通过proxy来达到gg送mm礼物的效果。\n",
    "\n",
    "代理模式主要包括三种类：\n",
    "- Subject类：例如IGiveGift类，定义了RealSubject和Proxy的功用接口，这样就在任何使用RealSubject的地方使用Proxy；\n",
    "- RealSubject类：例如Boy类，定义Proxy所代表的真实实体；\n",
    "- Proxy类：例如Porxy类，保存一个引用是的代理可以访问实体，并提供一个于Subject的接口相同的接口，这样代理就可以用来代替实体；\n",
    "\n",
    "代理模式应用主要包括以下几种：\n",
    "- 远程代理，也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实[DP]。\n",
    "- 虚拟代理，是根据需要创建开销很大的对象。通过它来存在实例化需要很长时间的真实对象[DP]。浏览器优化下载就是用的代理模式，例如打开一个很大的HTML网页时，里面可能由很多文字和图片，但是依然可以很快打开，优先看到文字，但是图片还在一张一张下载。哪些未打开的图片框，就是通过虚拟代理来替代真实图片，此时代理存储了真实图片的路径和尺寸。\n",
    "- 安全代理，用来控制真实对象访问时的权限[DP]。一般用于对象应该有不同的访问权限的时候。\n",
    "- 智能指引，是指当调用真实的对象时，代理处理另外一些事[DP]。例如计算真实对象的引用次数，这样当该对象没有引用时，可以自动释放它；或者当第一引用一个持久对象时，将它装入内存；或在访问一个实际对象前，检查是否已经锁定它，以确保其他对象不能改变它。这些都是通过代理在访问一个对象时附加一些内务处理。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
